package com.miplus.ccrm.uploadjob.service;

import com.alibaba.fastjson.JSONObject;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.miplus.ccrm.common.JPubUtils;
import com.miplus.ccrm.common.JTimer;
import com.miplus.ccrm.uploadjob.mapper.AsrCallhistMapper;
import com.miplus.ccrm.uploadjob.mapper.TRecorderMapper;
import com.miplus.ccrm.uploadjob.pojo.AsrCallhist;
import com.miplus.ccrm.uploadjob.pojo.TRecorder;
import com.miplus.ccrm.uploadjob.service.imaging.ImagingPlatformService;
import com.miplus.ccrm.uploadjob.service.imaging.req.ImagingResVo;
import com.miplus.ccrm.uploadjob.service.qm.QmDataService;
import com.miplus.ccrm.uploadjob.service.xsky.XSkyService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.util.FileUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class JCheckTimer extends JTimer {
    @Value("${cti.recordfileDir}")
    private String cti_recfileDir;
    @Value("${cti.uploadcheckday}")
    private Integer cti_uploadcheckday;
    @Value("${cti.uploadcheckspan}")
    private Integer cti_uploadcheckspan;
    @Value("${cti.uploadokremove}")
    private String cti_uploadokremove;
    @Value("${cti.recorderip}")
    private String cti_recorderip;
    @Value("${cti.recfilebakdir}")
    private String cti_recfilebakdir;
    @Value("${ccrm.recfile.savemode:}")
    private String recfile_savemode;
    @Value("${ai.asr.url:}")
    private String asr_url;
    @Value("${ai.asr.userid:}")
    private String asr_userid;
    @Value("${ai.asr.token:}")
    private String asr_token;
    @Value("${ai.asr.mp3:}")
    private String asr_mp3;
    @Value("${ai.asr.maxsesscnt:}")
    private Integer asr_maxsesscnt;
    @Resource
    private TRecorderMapper tRecorderMapper;
    @Resource
    private XSkyService ossServiceFile;

    @Resource
    private ImagingPlatformService imagingPlatformService;

    private String todayFilebakDir="";
    @Resource
    private AsrCallhistMapper asrCallhistMapper;
    @Resource
    private QmDataService qmDataService;

    public JCheckTimer()
    {
    }

    public int InitTimer()
    {
        log.info("InitTimer:uploadcheckspan={}",cti_uploadcheckspan);

        return this.StartTimer("timer",cti_uploadcheckspan);
    }

    @Override
    public boolean OnTimer()
    {
        try {
            if(JPubUtils.IsEmpty(cti_recorderip)){
                cti_recorderip=JPubUtils.getLocalIPAddr();
            }
            if (JPubUtils.IsEqual(recfile_savemode, "xsky")) {
                CheckUploadBakDir();
                OnUploadRecord();
            }

            if (JPubUtils.IsEqual(recfile_savemode, "imageService")) {
                CheckUploadBakDir();
                OnUploadImgRecord();
            }

            if (JPubUtils.IsNotEmpty(asr_url)) {
                OnRecordAsrResult();
                OnRecordAsrParse();
            }

            log.info("OnTimer.Done:{}",this.isRunning);
        }
        catch (Exception e){
            log.warn("OnTimer.Err:{}",e.getMessage());
        }

        return true;
    }

    private void CheckUploadBakDir()
    {//2024-10-09
        todayFilebakDir="";
        if(JPubUtils.IsEmpty(cti_recfilebakdir)){
            log.info("CheckUploadBakDir.NoSet:cti.recfilebakdir");
            return;
        }
        log.info("CheckUploadBakDir:{}",cti_recfilebakdir);
        try {
            File file = new File(cti_recfilebakdir);
            if (!file.exists()) {
                log.info("CheckUploadBakDir:Create Dir={}", cti_recfilebakdir);
                file.mkdirs();
            }
            todayFilebakDir = cti_recfilebakdir;
            if (!todayFilebakDir.endsWith("/")) {
                todayFilebakDir += "/";
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            todayFilebakDir += sdf.format(new Date());
            file = new File(todayFilebakDir);
            if (!file.exists()) {
                log.info("CheckUploadBakDir:Create today={}", todayFilebakDir);
                file.mkdirs();
            }
        }
        catch (Exception e){
            todayFilebakDir="";
            log.error("CheckUploadBakDir:{}",e.getMessage());
        }
    }

    private void OnUploadRecord()
    {
        int iday=0-cti_uploadcheckday;
        Date gedt=JPubUtils.addDays(new Date(),iday);
        log.info("OnUploadRecord:recorderip={},iday={},gedt={}",
                cti_recorderip,iday,JPubUtils.DTimeToString(gedt)
        );
        List<TRecorder> recorderList =tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .ge("starttime", gedt)
                        .eq("available","1")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip),"recorderip",cti_recorderip)
                        .exists("select 1 from report_call_hist h where h.CALLMANAGENUMBER=t.CALLID and h.ENDDATETIME is not null")
                        .apply("(taskflag is null or taskflag in ('0','-1','-2'))")
                        .last("limit 200")
        );
        if(JPubUtils.IsEmpty(recorderList)){
            log.info("OnUploadRecord.IsNull");
            return;
        }
        for(TRecorder rec : recorderList){
            String recid = rec.getRecorderid();
            try {
                String filename = rec.getFilename();
                String filepath="";
                if(JPubUtils.IsEqual(rec.getAgentid(),"qm")||
                        JPubUtils.IsEqual(rec.getAgentid(),"ivr")){
                    filepath=rec.getFilepath()+filename;
                }
                else {
                    filepath = getRecFilePathName(filename, rec.getFilepath());
                }
                File file = new File(filepath);
                TRecorder tRecorder = new TRecorder();
                tRecorder.setRecorderid(recid);
                tRecorder.setUploaddt(new Date());
                tRecorder.setInfotype("XSKY");
                boolean uploadok = false;
                log.info("OnUploadRecord({}):file={},size={}", recid, filepath,file.length());
                if (file.exists()) {
                    if (ossServiceFile.UploadFile(filename, file)) {
                        tRecorder.setInfoid(filename);
                        tRecorder.setInfodepart(String.format("SUCCESS:%d",file.length()));
                        uploadok = true;
                    } else {
                        Integer failcnt=JPubUtils.StringToInt(rec.getInfoid());
                        failcnt=failcnt-1;
                        tRecorder.setInfoid(failcnt.toString());
                        tRecorder.setInfodepart("FAIL");
                    }
                } else {
                    tRecorder.setInfoid("-99");
                    tRecorder.setInfodepart("File.NoExist");
                }
                log.info("OnUploadRecord({}):Result={}", recid, tRecorder.getInfodepart());

                tRecorderMapper.updateById(tRecorder);

                if (uploadok){
                    if(JPubUtils.IsEqual(cti_uploadokremove, "1")) {
                        DeleteFile(file, filename);
                    }
                    else if(JPubUtils.IsNotEmpty(todayFilebakDir)){
                        RemoveFile(file,filename,todayFilebakDir);
                    }
                }
            }
            catch (Exception e){
                log.warn("OnUploadRecord({}).Err:{}",recid,e.getMessage());
                e.printStackTrace();
            }
        }
    }

    private void OnUploadImgRecord()
    {
        int iday=0-cti_uploadcheckday;
        Date gedt=JPubUtils.addDays(new Date(),iday);
        log.info("OnUploadRecord:recorderip={},iday={},gedt={}",
                cti_recorderip,iday,JPubUtils.DTimeToString(gedt)
        );
        List<TRecorder> recorderList =tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .ge("starttime", gedt)
                        .eq("available","1")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip),"recorderip",cti_recorderip)
                        .exists("select 1 from report_call_hist h where h.CALLMANAGENUMBER=t.CALLID and h.ENDDATETIME is not null")
                        .apply("(backupsflag is null or backupsflag in ('0','-1','-2'))")
                        .last("limit 200")
        );
        if(JPubUtils.IsEmpty(recorderList)){
            log.info("OnUploadRecord.IsNull");
            return;
        }
        for(TRecorder rec : recorderList){
            String recid = rec.getRecorderid();
            try {
                String filename = rec.getFilename();
                String filepath="";
                if(JPubUtils.IsEqual(rec.getAgentid(),"qm")||
                        JPubUtils.IsEqual(rec.getAgentid(),"ivr")){
                    filepath=rec.getFilepath()+filename;
                }
                else {
                    filepath = getRecFilePathName(filename, rec.getFilepath());
                }
                File file = new File(filepath);
                TRecorder tRecorder = new TRecorder();
                tRecorder.setRecorderid(recid);
                tRecorder.setUploaddt(new Date());
                tRecorder.setInfotype("imageService");
                boolean uploadok = false;
                log.info("OnUploadRecord({}):file={},size={}", recid, filepath,file.length());
                if (file.exists()) {
                    ImagingResVo imagingResVo = imagingPlatformService.UploadFile(filename, filepath);
                    log.info("imagingResVo:"+imagingResVo.toString());
                    if(imagingResVo.getId()!=null){
                        tRecorder.setInfoid(imagingResVo.getId());
                        tRecorder.setInfodepart(String.format("SUCCESS:%d",file.length()));
                        tRecorder.setInfofileurl(imagingResVo.getUrl());
                        tRecorder.setBackupsflag("1");
                    }else {
                        Integer failcnt=JPubUtils.StringToInt(rec.getInfoid());
                        failcnt=failcnt-1;
                        tRecorder.setInfoid(failcnt.toString());
                        tRecorder.setInfodepart("FAIL");
                        tRecorder.setBackupsflag(failcnt.toString());
                    }
                } else {
                    tRecorder.setInfoid("-99");
                    tRecorder.setInfodepart("File.NoExist");
                }
                log.info("OnUploadRecord({}):Result={}", recid, tRecorder.getInfodepart());

                tRecorderMapper.updateById(tRecorder);

                if (uploadok){
                    if(JPubUtils.IsEqual(cti_uploadokremove, "1")) {
                        DeleteFile(file, filename);
                    }
                    else if(JPubUtils.IsNotEmpty(todayFilebakDir)){
                        RemoveFile(file,filename,todayFilebakDir);
                    }
                }
            }
            catch (Exception e){
                log.warn("OnUploadRecord({}).Err:{}",recid,e.getMessage());
                e.printStackTrace();
            }
        }
    }

    private void DeleteFile(File file,String filename)
    {
        log.info("DeleteFile:{}",filename);
        try {
            file.delete();
        }
        catch (Exception e){
            log.warn("DeleteFile.Err:{}",e.getMessage());
        }
    }

    private void RemoveFile(File file,String filename,String tofiledir)
    {
        log.info("RemoveFile:{} To {}",filename,tofiledir);
        try {
            File tofile = new File(tofiledir+"/"+filename);
            FileUtil.copyFile(file,tofile);

            DeleteFile(file,filename);
        }
        catch (Exception e){
            log.warn("RemoveFile.Err:{}",e.getMessage());
        }
    }

    private String getRecFilePathName(String filename,String path)
    {
        String fpath = cti_recfileDir + path;
        if (!fpath.endsWith("/")) {
            fpath = fpath + "/";
        }
        return fpath+filename;
    }

    private void OnRecordAsrParse()
    {
        int iday=0-cti_uploadcheckday;
        Date gedt=JPubUtils.addDays(new Date(),iday);
        log.info("OnRecordAsrParse:recorderip={},iday={},gedt={},maxsesscnt={}",
                cti_recorderip,iday,JPubUtils.DTimeToString(gedt),asr_maxsesscnt
        );
        List<TRecorder> recorderList =tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .selectAll(TRecorder.class)
                        .ge(TRecorder::getStarttime, gedt)
                        .eq(TRecorder::getAvailable,"1")
                        .ne(TRecorder::getAgentid,"ivr")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip),"recorderip",cti_recorderip)
                        .exists("select 1 from report_call_hist h where h.CALLMANAGENUMBER=t.CALLID and h.ENDDATETIME is not null")
                        .apply("(taskflag is null or taskflag in ('0','-1','-2'))")
                        .last("limit "+asr_maxsesscnt.toString())
        );
        if(JPubUtils.IsEmpty(recorderList)){
            //下面是导入的文件数据
            recorderList =tRecorderMapper.selectList(
                    new MPJLambdaWrapper<TRecorder>()
                            .selectAll(TRecorder.class)
                            .ge(TRecorder::getStarttime, gedt)
                            .eq(TRecorder::getAvailable,"1")
                            .eq(TRecorder::getAgentid,"qm")
                            .apply("(taskflag is null or taskflag in ('0','-1','-2'))")
                            .last("limit "+asr_maxsesscnt.toString())
            );
        }
        if(JPubUtils.IsEmpty(recorderList)){
            log.info("OnRecordAsrParse.IsNull");
            return;
        }

        for(TRecorder rec : recorderList){
            String recid=rec.getRecorderid();
            String filepath="";
            String filename=rec.getFilename();
            if(JPubUtils.IsEqual(rec.getAgentid(),"qm")||
                    JPubUtils.IsEqual(rec.getAgentid(),"ivr")){
                filepath=rec.getFilepath()+filename;
            }
            else {
                filepath = getRecFilePathName(filename, rec.getFilepath());
            }
            File file = new File(filepath);
            TRecorder tRecorder = new TRecorder();
            tRecorder.setRecorderid(recid);
            tRecorder.setUpasrdt(new Date());
            if(file.exists()){
                log.info("OnRecordAsrParse({}):file={}", recid,filepath);
                String urlasrfile=DoAsrRequest(file);
                log.info("OnRecordAsrParse({}):Result:{}", recid,urlasrfile);
                if(JPubUtils.IsEmpty(urlasrfile)){//fail
                    Integer failcnt=JPubUtils.StringToInt(rec.getTaskflag());
                    failcnt=failcnt-1;
                    tRecorder.setTaskflag(failcnt.toString());
                }
                else {//success
                    tRecorder.setTaskmark(urlasrfile);
                    tRecorder.setTaskflag("1");
                }
            }
            else{
                log.warn("OnRecordAsrParse:{} NoFind", filepath);
                tRecorder.setTaskmark("File.NoExist");
                tRecorder.setTaskflag("-99");
            }
            tRecorderMapper.updateById(tRecorder);
        }
    }

    private String DoAsrRequest(File uploadfile)
    {
        String urlasrfile="";
        String urlbody=asr_url+"dotcmultispksplit3?lanid=0";
        //String wavfile="E:/Sound/1101.wav";
        log.info("DoAsrRequest:{}", urlbody);
        try {
            HttpResponse<JsonNode> response = Unirest.post(urlbody)
                    .field("userid", asr_userid)
                    .field("token", asr_token)
                    .field("asr", "1")
                    .field("mp", "0")
                    .field("file", uploadfile)
                    .field("mp3", asr_mp3)
                    .asJson();
            log.info("DoAsrRequest.Response:{}", response.getBody());
            int status = response.getStatus();
            if (status == 200) {
                JsonNode responseBody = response.getBody();
                String code = responseBody.getObject().getString("errCode");
                if (JPubUtils.IsEqual(code, "0")) {
                    urlasrfile = responseBody.getObject().getString("result");
                } else {
                    log.warn("DoAsrRequest.Fail:code={}", code);
                }
            } else {
                log.warn("DoAsrRequest.Fail:status={}", status);
            }
        }
        catch (Exception e){
            log.error("DoAsrRequest.Err:{}", e.getMessage());
        }

        return urlasrfile;
    }

    private void OnRecordAsrResult()
    {
        int iday=0-cti_uploadcheckday;
        Date gedt=JPubUtils.addDays(new Date(),iday);
        log.info("OnRecordAsrResult:recorderip={},iday={},gedt={}",
                cti_recorderip,iday,JPubUtils.DTimeToString(gedt)
        );
        List<TRecorder> recorderList =tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .ge(TRecorder::getStarttime, gedt)
                        .ne(TRecorder::getAgentid,"ivr")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip),"recorderip",cti_recorderip)
                        .eq(TRecorder::getTaskflag,"1")
        );
        if(JPubUtils.IsEmpty(recorderList)){
            log.info("OnRecordAsrResult.IsNull");
            return;
        }

        for(TRecorder rec : recorderList){
            String fileurl=rec.getTaskmark();
            if(JPubUtils.IsEmpty(fileurl)){//理论上不存在
                log.warn("OnRecordAsrResult.Result Null");
            }
            else {
                DoParseAsrResult(fileurl,rec);
            }
        }
    }

    public String GetNextUID(String iden,Integer index)
    {
        String s =String.valueOf((new Date()).getTime());
        s += index.toString();
        if(iden!=null) s+="." + iden;
        return s;
    }

    private void DoParseAsrResult(String fileurl,TRecorder rec)
    {
        String urlbody=asr_url+"tts/"+fileurl;
        try {
            log.info("DoParseAsrResult:{}", urlbody);
            //这样也可以取，但是对大数据量不太好处理
            //HttpResponse<String> response = Unirest.get(urlbody).asString();
            //log.info("DoAsrParse.Response:{}", response.getBody());
            //int status = response.getStatus();
            //if (status == 200) {
            URL url=new URL(urlbody);
            InputStream inputStream = url.openStream();
            BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));
            String line;
            Integer index=0;
            while ((line=reader.readLine())!=null) {
                //String ss = response.getBody();
                //String[] arr = ss.split("\n");
                //for (int k = 0; k < arr.length; k++) {
                    //if (JPubUtils.IsEmpty(arr[k]) || arr[k].length() < 5)
                    //    continue;
                log.info("DoParseAsrResult:{}",line);
                if (JPubUtils.IsNotEmpty(line) && line.length() >5) {
                    JSONObject o = JSONObject.parseObject(line);
                    InsertAsrHist(index,rec,o);
                    index++;
                }
                    //log.info("DoAsrParse:s={},e={},i={},text={}", s, e, i, text);
               //}
            }
            reader.close();
            inputStream.close();

            log.info("DoParseAsrResult({}).SetTaskFlag=2", rec.getRecorderid());
            TRecorder tRecorder = new TRecorder();
            tRecorder.setRecorderid(rec.getRecorderid());
            tRecorder.setTaskflag("2");
            tRecorderMapper.updateById(tRecorder);

            qmDataService.SetQmDataReady(rec.getCallid());
            //} else {
             //   log.warn("DoAsrParse.Fail:status={}", status);
            //}
        }
        catch (Exception e){
            log.error("DoParseAsrResult.Err:{}", e.getMessage());
        }
    }

    private int InsertAsrHist(Integer index,TRecorder rec,JSONObject o)
    {
        try{
            Integer s = o.getInteger("s");
            Integer e = o.getInteger("e");
            String text = o.getString("text");
            if(JPubUtils.IsEmpty(text)){
                return 0;
            }
            Integer i =-1;
            Object obj=o.get("i");
            if(obj!=null) {
                i=o.getInteger("i");
            }
            AsrCallhist callhist = new AsrCallhist();
            String dn = rec.getChanneldn();

            String asrid = GetNextUID(dn, index);
            callhist.setAsrid(asrid);
            callhist.setDn(dn);
            callhist.setAgentid(rec.getAgentid());
            callhist.setCallid(rec.getCallid());
            callhist.setAni(rec.getTelno());
            callhist.setDnis(rec.getTeldnis());
            callhist.setAsrcontent(text);
            if(i<0){//表示是单通道录音
                callhist.setAsrstatus("channel");
            }
            else if (i == 1) {
                callhist.setAsrstatus("cust");
            } else {
                callhist.setAsrstatus("agent");
            }
            callhist.setCrdt(new Date());
            callhist.setAsrindex(index);
            callhist.setCalldir(rec.getCalltype());
            callhist.setStatus("1"); //0=实时，1=离线
            if (e > s) {
                BigDecimal span = new BigDecimal((e - s) / 1000.0);
                callhist.setSpan(span);
            } else {
                callhist.setSpan(new BigDecimal(0.0));
            }
            return asrCallhistMapper.insert(callhist);
        }
        catch (Exception e){
            log.error("InsertAsrHist.Err:{}",e.getMessage());
            return -1;
        }
    }
}
